<?php
/**
 * SuggestRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-06-16 15:18:37
 * @modified    2023-06-16 15:18:37
 *
 */

namespace App\Repositories;

use App\Http\Resources\SuggestResource;
use App\Models\DictModel;
use App\Models\Notification;
use App\Models\Project;
use App\Models\Suggest;
use App\Models\UserModel;
use Carbon\Carbon;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class SuggestRepo
{
    const STATUS_PENDING = 'pending';
    const STATUS_DONE = 'done';
    const STATUS_CLOSED = 'closed';

    public static function status()
    {
        return [
            self::STATUS_PENDING => '未处理',
            self::STATUS_DONE => '已处理',
            self::STATUS_CLOSED => '已关闭'
        ];
    }

    public static function params()
    {
        $dictNamePrefix = '意见管理';

        $dictLevel = '问题级别';
        $dictSource = '来源';
        $dictCategory = '问题分类';

        $builder = DictModel::query()
            ->select(['dd.name as item_name', 'dict.name'])
            ->join('dict_data as dd', 'dd.dict_id', '=', 'dict.id')
            ->where('dict.name', 'like', "{$dictNamePrefix}%");
        $dicts = $builder->get()->groupBy('name')->toArray();

        $levels = $sources = $categories = [];
        foreach ($dicts as $key => $dict) {
            foreach ($dict as $item) {
                if ($key == "{$dictNamePrefix}-{$dictLevel}") {
                    $levels[] = $item['item_name'];
                }
                if ($key == "{$dictNamePrefix}-{$dictSource}") {
                    $sources[] = $item['item_name'];
                }
                if ($key == "{$dictNamePrefix}-{$dictCategory}") {
                    $categories[] = $item['item_name'];
                }
            }
        }

        return [
            'level' => $levels,
            'source' => $sources,
            'category' => $categories
        ];
    }

    public static function delete($id)
    {
        $suggest = Suggest::find($id);
        if (empty($suggest) || !$suggest->mark) {
            throw new \Exception('意见反馈不存在');
        }
        $suggestInfo = self::getDetail($suggest);
        $suggestInfo = $suggestInfo->toArray($suggestInfo);

        if (!$suggestInfo['button_delete']) {
            throw new \Exception('当前意见反馈不允许删除');
        }

        Notification::query()
            ->where('business_type', NotificationRepo::TYPE_SUGGEST)
            ->where('business_id', $id)
            ->delete();

        $suggest->mark = 0;
        $suggest->saveorFail();
    }

    public static function close($id)
    {
        $suggest = Suggest::find($id);
        if (empty($suggest) || !$suggest->mark) {
            throw new \Exception('意见反馈不存在');
        }
        $suggestInfo = self::getDetail($suggest);
        $suggestInfo = $suggestInfo->toArray($suggestInfo);
        if (!$suggestInfo['button_close']) {
            throw new \Exception('当前意见反馈不允许关闭');
        }

        $suggest->status = self::STATUS_CLOSED;
        $suggest->saveorFail();

        return self::getInfo($id);
    }

    public static function export()
    {
        $data = self::getList()->toArray();
        $suggests = $data['data'];

        $results = [];
        foreach ($suggests as $suggest) {
            $resource = (new SuggestResource($suggest))->toArray($suggest);
            $results[] = [
                ' ' . $resource['id'],
                ' ' . $resource['title'],
                ' ' . $resource['project_name'],
                ' ' . $resource['create_user_name'],
                ' ' . $resource['charge_user_name'],
                ' ' . $resource['create_time'],
                ' ' . implode(',', $resource['resolve_user_names']),
                ' ' . $resource['status_text'],
                ' ' . $resource['resolve_time'],
            ];
        }
        $pathPrefix = 'downloads/suggests/' . date('Y/m/d/');
        $prefix = public_path() . '/' . $pathPrefix;
        $excelFileName = 'suggest-' . md5(date('YmdHis') . microtime()) . '.xlsx';
        if (!is_dir($prefix)) {
            mkdir($prefix, 0777, true);
        }
        $excelFilePath = $prefix . $excelFileName;
        $spreadsheet = new Spreadsheet();
        $sheet = new Worksheet($spreadsheet, "意见反馈");
        $spreadsheet->addSheet($sheet);
        $spreadsheet->removeSheetByIndex(0);

        $excelData = [];
        $excelData[] = [
            'ID',
            '问题标题',
            '关联任务',
            '问题提出人',
            '问题负责人',
            '创建时间',
            '解决人',
            '状态',
            '处理时间'
        ];

        $suggestData = $results;
        $suggestData = array_merge($excelData, $suggestData);

        $sheet->fromArray($suggestData);
        $writer = new Xlsx($spreadsheet);
        $writer->save($excelFilePath);
        return env('APP_URL') . '/' . $pathPrefix . $excelFileName;
    }

    public static function resolve($id)
    {
        $data = self::validateResolveDate($id);

        $mainData = $data['main'];

        $resolveUsers = [];
        foreach ($data['user_ids'] as $item) {
            $resolveUsers[] = new Suggest\Resolve\User([
                'user_id' => $item
            ]);
        }

        $resolve = new Suggest\Resolve();
        $resolve->fill($mainData);
        $resolve->saveOrFail();
        $resolve->users()->saveMany($resolveUsers);

        $suggest = Suggest::find($id);
        $suggest->status = self::STATUS_DONE;
        $suggest->saveOrFail();

        return self::getInfo($id);
    }

    private static function validateResolveDate($id)
    {
        $suggest = Suggest::find($id);
        if (empty($suggest) || !$suggest->mark) {
            throw new \Exception('意见反馈不存在');
        }
        $suggestInfo = self::getInfo($id);
        $suggestInfo = $suggestInfo->toArray($suggest);
        if (!$suggestInfo['button_done']) {
            throw new \Exception('当前意见反馈不允许执行解决操作');
        }

        $params = self::params();
        $data = request()->getContent();
        $arr = json_decode($data, true);

        $categories = $params['category'];

        $category = $arr['category'] ?? '';
        if (!in_array($category, $categories)) {
            throw new \Exception('分类错误');
        }
        $resolveDate = $arr['resolve_date'] ?? '';
        if (!$resolveDate) {
            throw new \Exception('请输入解决时间');
        }
        try {
            $resolveDate = Carbon::parse($resolveDate)->toDateTimeString();
        } catch (\Exception $e) {
            throw new \Exception('解决时间错误');
        }

        $users = $arr['user_ids'] ?? [];
        if (empty($users)) {
            throw new \Exception('请选择问题解决人');
        }

        $userIds = [];
        foreach ($users as $user) {
            $itemUser = UserModel::find((int)$user);
            if (empty($itemUser) || !$itemUser->mark) {
                throw new \Exception('问题解决人不存在(ID: ' . (int)$user . ')');
            }
            $userIds[] = (int)$user;
        }

        if (!$userIds) {
            throw new \Exception('请选择问题解决人');
        }

        $reason = trim($arr['reason'] ?? '');
        $scheme = trim($arr['scheme'] ?? '');
        $description = trim($arr['description'] ?? '');

        return [
            'main' => [
                'suggest_id' => $id,
                'category' => $category,
                'resolve_date' => $resolveDate,
                'reason' => $reason,
                'scheme' => $scheme,
                'description' => $description
            ],
            'user_ids' => $userIds
        ];
    }

    public static function getList()
    {
        $perPage = intval(request('limit') ?? 10);
        $keyword = trim(request('keyword') ?? '');
        $projectId = intval(request('project_id') ?? '');
        $builder = Suggest::query();
        $builder->where('mark', 1);
        $builder->with(['resolve.users.user']);
        $builder->orderByDesc('update_time')
            ->orderByDesc('create_time');
        if ($keyword) {
            $builder->where(function ($query) use ($keyword) {
                $query->where('suggest.title', 'like', "%{$keyword}%")
                    ->orWhere('suggest.source', 'like', "%{$keyword}%")
                    ->orWhere('suggest.level', 'like', "%{$keyword}%");
            });
        }
        if ($projectId) {
            $builder->where('project_id', $projectId);
        }
        $results = $builder->paginate($perPage);
        $results->transform(function ($suggest) {
            return new SuggestResource($suggest);
        });
        return $results;
    }

    public static function store(int $id)
    {
        $data = self::validateRequestData($id);

        if (!$id) {
            $suggest = new Suggest();
        } else {
            $suggest = Suggest::find($id);
            $suggestInfo = self::getInfo($id);
            $suggestInfo = $suggestInfo->toArray($suggest);
            if (!$suggestInfo['button_modify']) {
                throw new \Exception('当前意见反馈不允许修改');
            }
        }

        $suggest->fill($data);
        $suggest->saveOrFail();

        $suggestId = $suggest->id;
        // 发送通知
        self::notifyPush($id, $suggestId, $data['charge_user_id']);
        return self::getInfo($suggestId);
    }

    public static function getInfo($id)
    {
        $suggest = Suggest::find($id);
        if (empty($suggest) || !$suggest->mark) {
            throw new \Exception('意见反馈不存在');
        }
        $suggest->with(['resolve.users.user']);
        return self::getDetail($suggest);
    }

    private static function getDetail($suggest)
    {
        return new SuggestResource($suggest);
    }

    /**
     * 发送通知
     *  新建: 直接发送
     *  编辑: 负责人改变了就发送
     * @param $id 提交时的ID，新建时为0, 用于判断是不是新增
     * @param $dbId 保存之后的ID
     * @param $newChargeUserId 提交的负责人ID，用于判断原始和新的是否一致
     */
    private static function notifyPush($id, $dbId, $newChargeUserId)
    {
        $suggest = Suggest::find($dbId);
        if (empty($suggest)) {
            return;
        }
        $userID = $suggest->charge_user_id;
        if ($id && $userID == $newChargeUserId) {
            return;
        }

        NotificationRepo::multiStore([$userID], $dbId, NotificationRepo::TYPE_SUGGEST, '意见反馈通知', $suggest->title);
    }

    private static function validateRequestData($id)
    {
        if ($id) {
            $suggest = Suggest::find($id);
            if (empty($suggest)) {
                throw new \Exception('意见反馈不存在');
            }
        }
        $params = self::params();
        $data = request()->getContent();
        $arr = json_decode($data, true);
        if (empty($arr)) {
            throw new \Exception('提交失败，请检查数据');
        }

        $title = trim($arr['title'] ?? '');
        if (!$title) {
            throw new \Exception('请填写标题');
        }

        $paramSource = $params['source'];

        $source = trim($arr['source'] ?? '');
        if (!$source) {
            throw new \Exception('请选择来源');
        }

        if (!in_array($source, $paramSource)) {
            throw new \Exception('来源错误');
        }

        $level = trim($arr['level'] ?? '');
        if (!$level) {
            throw new \Exception('请选择级别');
        }
        $paramLevel = $params['level'];
        if (!in_array($level, $paramLevel)) {
            throw new \Exception('级别错误');
        }

        $projectId = intval($arr['project_id'] ?? 0);
        if (!$projectId) {
            throw new \Exception('请选择关联项目');
        }
        $project = Project::find($projectId);
        if (empty($project) || !$project->mark) {
            throw new \Exception('关联项目不存在');
        }
        $taskId = intval($arr['task_id'] ?? 0);
        if (!$taskId) {
            // throw new \Exception('请选择关联任务');
        }

//        $task = Project\Task::find($taskId);
//        if (empty($task) || !$task->mark) {
//            throw new \Exception('任务不存在');
//        }

//        $projectTaskIds = $project->tasks->pluck('id')->toArray();
//        if (!in_array($taskId, $projectTaskIds)) {
//            throw new \Exception('关联任务非当前项目所有');
//        }

        $chargeUserId = intval($arr['charge_user_id'] ?? 0);
        if (!$chargeUserId) {
            throw new \Exception('请选择问题负责人');
        }
        $chargeUser = UserModel::find($chargeUserId);
        if (empty($chargeUser) || !$chargeUser->mark) {
            throw new \Exception('所选问题负责人不存在');
        }

        $result = [
            'title' => $title,
            'source' => $source,
            'level' => $level,
            'project_id' => $projectId,
            'task_id' => $taskId,
            'charge_user_id' => $chargeUserId,
            'create_user_id' => registry('user_id'),
            'description' => $arr['description'] ?? '',
            'status' => self::STATUS_PENDING
        ];
        return $result;
    }
}